
package jp.ize.iwp.utils.sync;

#if flash9
import flash.events.EventDispatcher;
#elseif flash
import jp.ize.iwp.avm1.events.EventDispatcher;
#end

/**
* SyncManager クラスです。<br />
* 複数の何らかの処理を同期させたいときに利用します。
*/
class SyncManager extends EventDispatcher
{
	// {{{ properties

	public var executings:Array<Int>;
	public var prepares:Array<Int>;
	public var count:Int;

	// }}}
	// {{{ public function new() : Void
	/**
	* コンストラクタです。
	*/
	public function new() : Void
	{
		super();
		executings = new Array();
		prepares   = new Array();
		count = 0;
	}

	// }}}
	// {{{ public function init() : Void
	/**
	* コンストラクタです。
	*/
	public function init() : Void
	{
		executings = new Array();
		for ( i in 0...prepares.length ) {
			executings.push(i);
		}
	}

	// }}}
	// {{{ public function createSyncUnit() : SyncUnit
	/**
	* 同期対象となるオブジェクトに対して新規に SyncUnit クラスインスタンスを生成し返します。
	* このSyncUnit インスタンスを利用することによりSyncManagerで同期を管理することが出来ます。
	*/
	public function createSyncUnit() : SyncUnit
	{
		var id:Int = count;
		var su:SyncUnit = new SyncUnit(this,id);
		prepares.push(id);
		executings.push(id);
		count++;
		return su;
	}

	// }}}
	// {{{ public function done( id:Int ) : Void
	/**
	* SyncUnit から処理が終了したことが通知されます。
	* SyncUnit から呼出されるので、直接呼出すことはありません。
	* 1つの処理が完了すると SyncEvent.COMPLETE イベントが発生します。
	* すべての処理が完了すると SyncEvent.ALL_COMPLETE イベントが発生します。
	* イベントは SyncManager のインスタンス自身に発生します。
	*/
	public function done( id:Int ) : Void
	{
		var e1:SyncEvent = new SyncEvent(SyncEvent.COMPLETE,true,true);
		executings.remove(id);
		e1.id = id;
		e1.rest  = executings.length;
		e1.total = prepares.length;
		e1.count = e1.total - e1.rest;
		dispatchEvent(e1);
		if ( executings.length<=0 ) {
			var e2:SyncEvent = new SyncEvent(SyncEvent.ALL_COMPLETE,true,true);
			dispatchEvent(e2);
		}
	}

	// }}}
	// {{{ public function error( id:Int, e:Dynamic ) : Void
	/**
	* SyncUnit から処理がエラーが発生したことが通知されます。
	* SyncUnit から呼出されるので、直接呼出すことはありません。
	* エラーが発生すると SyncEvent.ERROR イベントが発生します。
	* イベントは SyncManager のインスタンス自身に発生します。
	*/
	public function error( id:Int, e:Dynamic ) : Void
	{
		var e1:SyncEvent = new SyncEvent(SyncEvent.ERROR,true,true);
		e1.id = id;
		e1.rest  = executings.length;
		e1.total = prepares.length;
		e1.count = e1.total - e1.rest;
		e1.error = e;
		dispatchEvent(e1);
	}

	// }}}
}
